package com.coder4j.config;

import com.coder4j.Application;
import com.coder4j.log.entity.ErrorLogEntity;
import com.coder4j.log.service.IErrorLogService;
import com.coder4j.starter.tools.vo.BaseException;
import com.coder4j.starter.tools.vo.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 *
 * @author Keller
 * @date 2022-06-27 10:02:08
 */
@RestControllerAdvice
@Slf4j
public class ExceptionAdviceController {

    @Resource
    private IErrorLogService errorLogService;

    /**
     * 包名
     */
    private String packageName = Application.class.getPackage().getName();

    /**
     * 要排除的 StackTraceElement
     */
    private final static String ExcludeElement = "SpringCGLIB";

    /**
     * 要排除的类前缀
     */
    private final static String ExcludeClassPrefix = "Base";

    @ExceptionHandler(value = Exception.class)
    public R handle(Exception e) {
        List<StackTraceElement> collect = Arrays.stream(e.getStackTrace())
                .filter(item -> item.getClassName().startsWith(packageName) && ! item.toString().contains(ExcludeElement))
                .collect(Collectors.toList());

        ErrorLogEntity entity = new ErrorLogEntity();
        entity.setErrorClass(e.getClass().getName());
        entity.setMessage(e.getMessage());

        StringBuilder sb = new StringBuilder();
        boolean setResource = false;
        for (StackTraceElement element : collect) {
            sb.append(element.toString());

            String fileName = element.getFileName();
            if(fileName != null && fileName.startsWith(ExcludeClassPrefix)){
                continue;
            }
            if(!setResource){
                entity.setSourceClass(element.getClassName());
                entity.setSourceMethod(element.getMethodName());
                entity.setSourceLine(element.getLineNumber());
                setResource = true;
            }
        }
        entity.setStackTrace(sb.toString());

        errorLogService.baseSave(entity);
        log.error("ExceptionHandler",e);

        if(e instanceof BaseException){
            return R.error(e.getMessage());
        }
        return R.error();
    }
}
